package com.ayuku.commons.ui;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Date;
import java.util.List;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;
import org.eclipse.wb.swt.SWTResourceManager;

import com.ayuku.commons.AYConst;
import com.ayuku.commons.Util;

public abstract class ListMasterForm extends Composite {
	private Table tableData;
	private Text fSearch;
	private Label lblMessage;
	private Button btnFind;
	private String funcId;
	private Object[][] data;

	/**
	 * Create the composite.
	 * 
	 * @param parent
	 * @param style
	 */
	public ListMasterForm(Composite parent, int style) {
		super(parent, style);

		data = new Object[10][];

		setLayout(new GridLayout(1, false));

		Composite composite = new Composite(this, SWT.NONE);
		composite.setLayout(new RowLayout(SWT.HORIZONTAL));
		composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false,
				1, 1));

		ToolBar toolBar = new ToolBar(composite, SWT.FLAT | SWT.RIGHT);

		ToolItem btnNew = new ToolItem(toolBar, SWT.NONE);
		btnNew.setImage(SWTResourceManager.getImage(ListMasterForm.class,
				"/images/form/database_add.png"));
		btnNew.setText("Add");

		btnNew.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent evt) {
				btnNewWidgetSelected(evt);
			}
		});

		ToolItem btnEdit = new ToolItem(toolBar, SWT.NONE);
		btnEdit.setImage(SWTResourceManager.getImage(ListMasterForm.class,
				"/images/form/database_edit.png"));
		btnEdit.setText("Edit");

		btnEdit.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent evt) {
				btnEditWidgetSelected(evt);
			}
		});

		ToolItem btnDelete = new ToolItem(toolBar, SWT.NONE);
		btnDelete.setImage(SWTResourceManager.getImage(ListMasterForm.class,
				"/images/form/database_delete.png"));
		btnDelete.setText("Delete");
		btnDelete.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent evt) {
				btnDeleteWidgetSelected(evt);
			}
		});
		ToolItem btnReload = new ToolItem(toolBar, SWT.NONE);
		btnReload.setImage(SWTResourceManager.getImage(ListMasterForm.class,
				"/images/form/database_refresh.png"));
		btnReload.setText("Refresh");
		btnReload.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent evt) {
				btnReloadWidgetSelected(evt);
			}
		});

		Composite composite_1 = new Composite(this, SWT.NONE);
		composite_1.setLayout(new GridLayout(4, false));
		composite_1.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false,
				false, 1, 1));

		Label lblNewLabel = new Label(composite_1, SWT.NONE);
		lblNewLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false,
				false, 1, 1));
		lblNewLabel.setText("Search");

		fSearch = new Text(composite_1, SWT.BORDER);
		fSearch.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false,
				1, 1));
		fSearch.setToolTipText("Kotak 'Pencarian' ketikkan data yang akan di cari di kotak ini kemudian tekan enter atau tekan tombol 'Pencarian'");
		fSearch.addKeyListener(new KeyAdapter() {
			public void keyReleased(KeyEvent evt) {
				fSearchKeyReleased(evt);
			}
		});
		btnFind = new Button(composite_1, SWT.NONE);
		btnFind.setImage(SWTResourceManager.getImage(ListMasterForm.class,
				"/images/form/zoom.png"));
		btnFind.setText("Go");
		btnFind.setToolTipText("Tombol 'Search' tekan tombol ini untuk memulai pencarian data");
		btnFind.setText(" Go ");
		btnFind.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent evt) {
				btnFindWidgetSelected(evt);
			}
		});

		Button btnClear = new Button(composite_1, SWT.NONE);
		btnClear.setText("Clear");
		btnClear.setToolTipText("Tombol 'Clear search' untuk menghapus kriteria pencarian yang diketikkan di kotak pencarian dan menampilkan data tanpa kriteria.");
		btnClear.setText("Reset");
		btnClear.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent evt) {
				btnClearWidgetSelected(evt);
			}
		});

		setTableData(new Table(this, SWT.VIRTUAL | SWT.MULTI
				| SWT.FULL_SELECTION | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL));

		getTableData().setLayoutData(
				new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
		getTableData().setHeaderVisible(true);
		getTableData().setLinesVisible(true);

		tableData.addKeyListener(new KeyAdapter() {
			public void keyPressed(KeyEvent evt) {
				tableDataKeyPressed(evt);
			}
		});

		tableData.addMouseListener(new MouseAdapter() {
			public void mouseDoubleClick(MouseEvent evt) {

				tableDataMouseDoubleClick(evt);

			}
		});

		lblMessage = new Label(this, SWT.NONE);
		lblMessage.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false,
				1, 1));
		lblMessage.setText("Info");

		final boolean dt = createTableColumn(getTableData());
		if (dt) {

			Thread thread = new Thread() {
				public void run() {

					Display.getDefault().syncExec(new Runnable() {
						public void run() {
							try {
								System.out
										.println("*** masuk load thread data ...");
								loadDataThread();
								System.out
										.println("*** masuk load thread data akhir ...");
							} catch (Exception e) {
								e.printStackTrace();
							}
						}
					});

				}
			};
			thread.start();
		}

		tableData.addListener(SWT.SetData, new Listener() {
			public void handleEvent(Event e) {
				TableItem item = (TableItem) e.item;
				int index = tableData.indexOf(item);
				Object[] datum = data[index];
				if (data.length > 0) {
					fillTable(datum, item);
				}
			}
		});

		// DON DELETE
		additionalProcess();

		// Add sort indicator and sort data when column selected
		Listener sortListener = new Listener() {
			public void handleEvent(Event e) {
				// determine new sort column and direction
				TableColumn sortColumn = tableData.getSortColumn();
				TableColumn currentColumn = (TableColumn) e.widget;
				int dir = tableData.getSortDirection();
				if (sortColumn == currentColumn) {
					dir = dir == SWT.UP ? SWT.DOWN : SWT.UP;
				} else {
					tableData.setSortColumn(currentColumn);
					dir = SWT.UP;
				}

				int s = 0;

				// sort the data based on column and direction
				for (int i = 0; i < tableData.getColumnCount(); i++) {
					if (currentColumn == tableData.getColumn(i)) {
						s = i;
					}
				}

				final int index = s;
				final int direction = dir;
				Arrays.sort(data, new Comparator<Object>() {
					public int compare(Object arg0, Object arg1) {
						Object[] a = (Object[]) arg0;
						Object[] b = (Object[]) arg1;
						if (a[index] == b[index])
							return 0;
						if (direction == SWT.UP) {

							if (a[index].getClass().equals(Integer.class)) {
								return ((Integer) a[index])
										.compareTo(((Integer) b[index])) > 0 ? -1
										: 1;
							} else if (a[index].getClass().equals(String.class)) {
								return ((String) a[index])
										.compareTo(((String) b[index])) > 0 ? -1
										: 1;
							} else if (a[index].getClass().equals(
									BigDecimal.class)) {
								return ((BigDecimal) a[index])
										.compareTo(((BigDecimal) b[index])) > 0 ? -1
										: 1;
							} else if (a[index].getClass().equals(Double.class)) {
								return ((Double) a[index])
										.compareTo(((Double) b[index])) > 0 ? -1
										: 1;
							} else if (a[index].getClass()
									.equals(Boolean.class)) {
								return ((Boolean) a[index])
										.compareTo(((Boolean) b[index])) > 0 ? -1
										: 1;
							} else if (a[index].getClass().equals(Long.class)) {
								return ((Long) a[index])
										.compareTo(((Long) b[index])) > 0 ? -1
										: 1;
							} else if (a[index].getClass().equals(Date.class)) {
								return ((Date) a[index])
										.compareTo(((Date) b[index])) > 0 ? -1
										: 1;
							} else {
								return ((Integer) a[index])
										.compareTo(((Integer) b[index])) > 0 ? -1
										: 1;
							}
						} else {

							if (a[index].getClass().equals(Integer.class)) {
								return ((Integer) a[index])
										.compareTo(((Integer) b[index])) < 0 ? -1
										: 1;
							} else if (a[index].getClass().equals(String.class)) {
								return ((String) a[index])
										.compareTo(((String) b[index])) < 0 ? -1
										: 1;
							} else if (a[index].getClass().equals(
									BigDecimal.class)) {
								return ((BigDecimal) a[index])
										.compareTo(((BigDecimal) b[index])) < 0 ? -1
										: 1;
							} else if (a[index].getClass().equals(Double.class)) {
								return ((Double) a[index])
										.compareTo(((Double) b[index])) < 0 ? -1
										: 1;
							} else if (a[index].getClass()
									.equals(Boolean.class)) {
								return ((Boolean) a[index])
										.compareTo(((Boolean) b[index])) < 0 ? -1
										: 1;
							} else if (a[index].getClass().equals(Long.class)) {
								return ((Long) a[index])
										.compareTo(((Long) b[index])) < 0 ? -1
										: 1;
							} else if (a[index].getClass().equals(Date.class)) {
								return ((Date) a[index])
										.compareTo(((Date) b[index])) < 0 ? -1
										: 1;
							} else {
								return ((Integer) a[index])
										.compareTo(((Integer) b[index])) < 0 ? -1
										: 1;
							}
						}

					}
				});

				tableData.setSortDirection(dir);
				tableData.clearAll();
			}
		};

		for (int i = 0; i < tableData.getColumnCount(); i++) {
			tableData.getColumn(i).addListener(SWT.Selection, sortListener);
		}

	}

	public String getFuncId() {
		return funcId;
	}

	public void setFuncId(String funcId) {
		this.funcId = funcId;
	}

	public Object[][] getData() {
		return data;
	}

	public void setData(Object[][] data) {
		this.data = data;
	}

	abstract protected void fillTable(Object[] obj, TableItem item);

	abstract protected String[] getColumCaption();

	abstract protected int[] getColumWidth();

	abstract protected void populateTable(String sqlDml) throws Exception;

	// abstract protected void loadAllData() throws Exception;

	// abstract protected void loadSearchData() throws Exception;

	abstract protected Integer doDelete(List<String> id) throws Exception;

	abstract protected void showEditForm();

	abstract public void printPreview();

	abstract public void showAddForm();

	abstract public void additionalProcess();

	private void btnClearWidgetSelected(SelectionEvent evt) {
		fSearch.setText("");
		loadDataThread();
	}

	protected int rowId;

	private final void btnReloadWidgetSelected(SelectionEvent evt) {
		loadDataThread();
		doFocusOnTableData();
	}

	private final void btnFindWidgetSelected(SelectionEvent evt) {
		loadDataThread();
		fSearch.setFocus();
	}

	@Override
	protected void checkSubclass() {
		// Disable the check that prevents subclassing of SWT components
	}

	public void setTableData(Table tableData) {
		this.tableData = tableData;
	}

	public Table getTableData() {
		return tableData;
	}

	private void fSearchKeyReleased(KeyEvent evt) {
		if (evt.keyCode == 13) {
			loadDataThread();
		}
	}

	public final Text getFSearch() {
		return fSearch;
	}

	public void loadSearchData() throws Exception {
		System.out.println("**** LOARD SEARCH DATA ****");
		populateTable("%" + getFSearch().getText() + "%");
	}

	public void loadAllData() throws Exception {
		System.out.println("**** LloadAllData ****");
		populateTable("%%");
	}

	public void loadDataThread() {
		try {
			loadSearchData();
			lblMessage.setText("Jumlah data:" + tableData.getItemCount());
		} catch (Exception e) {
			e.printStackTrace();
			Util.showMsgBox("Gagal load: " + e.getMessage(), 1, getShell());
		}
		fSearch.setFocus();
	}

	public final boolean createTableColumn(Table tableData) {
		tableData.setLinesVisible(true);
		tableData.setHeaderVisible(true);

		boolean rtrValue = true;
		final String[] titles = getColumCaption();
		int[] col = getColumWidth();

		if (titles.length != col.length) {
			System.out
					.println("DATA JUDUL KOLOM DENGAN DATA LEBAR KOLOM TIDAK SAMA");
		}

		if (titles.length == 0) {
			rtrValue = false;
		}

		for (int i = 0; i < titles.length; i++) {
			TableColumn column = new TableColumn(tableData, SWT.NONE);
			column.setText(titles[i]);
		}

		if (col.length == 0) {
			rtrValue = false;
		}

		for (int i = 0; i < col.length; i++) {
			tableData.getColumn(i).setWidth(col[i]);
		}

		tableData.getColumn(0).setResizable(false);

		return rtrValue;
	}

	private final void tableDataKeyPressed(KeyEvent evt) {
		if (evt.keyCode == 13) {

			showEditForm();
			if (Util.OPERATION_CODE > 0) {
				loadDataThread();
				Util.OPERATION_CODE = 0;
			}

		}
	}

	private final void tableDataMouseDoubleClick(MouseEvent evt) {

		showEditForm();
		if (Util.OPERATION_CODE > 0) {
			loadDataThread();
			Util.OPERATION_CODE = 0;
		}
	}

	private final void btnNewWidgetSelected(SelectionEvent evt) {

		showAddForm();
		if (Util.OPERATION_CODE > 0) {
			loadDataThread();
			Util.OPERATION_CODE = 0;
		}
		doFocusOnTableData();
	}

	private void doFocusOnTableData() {
		tableData.setFocus();
		if (tableData.getItemCount() > 0 && tableData.getSelectionCount() < 1) {
			tableData.select(0);
		}
	}

	private final void btnEditWidgetSelected(SelectionEvent evt) {

		showEditForm();
		if (Util.OPERATION_CODE > 0) {
			loadDataThread();
			Util.OPERATION_CODE = 0;
		}
		doFocusOnTableData();
	}

	private final void btnDeleteWidgetSelected(SelectionEvent evt) {

		deleteData();
		doFocusOnTableData();
	}

	public final String deleteData() {
		TableItem[] items = tableData.getSelection();
		List<String> lst = new ArrayList<String>();
		if ((items == null) || (items.length < 1)) {
			Util.showMsgBox(AYConst.FAIL_DELETE, AYConst.MSG_WARN, getShell());
		} else {

			try {
				MessageBox messageBox = new MessageBox(getShell(), SWT.OK
						| SWT.CANCEL | SWT.ICON_WARNING);
				messageBox
						.setMessage("Anda Yakin akan menghapus data yang anda pilih?");
				if (messageBox.open() == SWT.OK) {

					for (int j = 0; j < items.length; j++) {
						TableItem itm = (TableItem) items[j];
						String idDelete = itm.getText(0);
						lst.add(idDelete);
					}

					if (lst.size() > 0) {
						doDelete(lst);
						loadDataThread();
					}

				}
			} catch (Exception e) {
				e.printStackTrace();

				if (e.getMessage().contains("FOREIGN KEY")) {
					Util.showMsgBox(
							"Data tidak dapat dihapus karena dipakai oleh table lain, silakan hapus terlebih dulu tabel yang pakai!, "
									+ e.getMessage(), 2, getShell());
				} else {
					Util.showMsgBox("Data yg dipilih gagal dihapus!, karena: "
							+ e.getMessage(), 2, getShell());
				}
			} finally {
				lst = null;
			}
		}

		return "success";
	}
}
